FEATURE: Visual workflow editing#21
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a new "Visual" tab in the workflow admin editor that allows admins to view and edit workflow steps as a swimlane/connector diagram (drag steps between category lanes, drag handles to create/retarget arrows, edit option labels inline, add/delete steps and connectors with confirmation dialogs). It also reorganizes the admin routes/templates from dash-separated nested route names to canonical dotted nested routes, converts several .hbs + JS template-only components to .gjs, and tightens up backend support (deleting a step now also deletes incoming/outgoing WorkflowStepOptions in a transaction, and the steps index endpoint returns related sibling categories for the lane view).
Changes:
- New
WorkflowVisualEditorcomponent (~2,500 lines) implementing swimlanes, orthogonal arrow routing with a heavy scoring system, drag-and-drop interactions, and connector option dropdowns; integrated as a tab inWorkflowEditor. - Admin route/template hierarchy renamed from
discourse-workflow-workflows-steps[-options[-edit]]to dotteddiscourse-workflow-workflows.steps.options.editform; templates migrated from.hbsto.gjs; tests and the route-source spec updated accordingly. - Backend:
WorkflowStepsController#destroywrapped in a transaction that removes related step options first;#indexnow also returnsworkflow_categories(sibling lane categories);WorkflowStepOptionsControllercovered by a new update spec.
Reviewed changes
Copilot reviewed 44 out of 50 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| admin/.../components/workflow-visual-editor.gjs | New ~2500-line component with routing, drag-drop, and rendering logic. |
| admin/.../components/workflow-editor.gjs | Adds List/Visual tabs and renders the new editor. |
| admin/.../components/workflow-step-editor.gjs | New .gjs extracted from prior .hbs/JS pair. |
| admin/.../components/workflow-list-editor.gjs, workflow-{back,deep-link,link}-button.gjs, workflow-step-list-editor.gjs, workflow-step-option-list-editor.gjs, workflow-step-option-editor.gjs | Path/import renames (discourse-common → discourse/...), @tracked → getter forwarding. |
| admin/.../routes/.../*.js | New route classes for workflows / steps; nested route names updated; new.js accepts category_id query param. |
| admin/.../templates/.../*.{hbs,gjs} | .hbs templates replaced with .gjs equivalents using @controller.* accessors. |
| app/controllers/.../workflow_steps_controller.rb | destroy now transactional + cascades step options; index adds workflow_categories. |
| assets/.../user-menu/workflow-notifications-list-empty-state.* | Template-only component replaced with class-based .gjs using trustHTML. |
| assets/.../connectors/.../z-workflow-burndown-chart.gjs | Wraps color_style in trustHTML. |
| assets/stylesheets/common/workflow_common.scss | Adds extensive styles for the visual editor. |
| config/locales/client.en.yml | New visual.* strings, fixes whitespace typos. |
| plugin.rb | Version bump 0.4.1 → 0.5.0. |
| spec/system/workflow_admin_visual_spec.rb, page_objects/pages/workflow_admin_visual.rb | New system spec and page-object harness (heavy use of evaluate_script). |
| spec/requests/admin/workflow_steps_controller_spec.rb, workflow_step_options_controller_spec.rb | New tests for cascade-delete and option update. |
| spec/lib/admin_route_source_spec.rb | Updated paths/expectations to match the new route layout. |
| test/javascripts/unit/routes/*.js | Updated lookup keys and module names to dotted form. |
Comments suppressed due to low confidence (1)
admin/assets/javascripts/discourse/components/workflow-visual-editor.gjs:2103
reorderStephas the same non-atomic swap problem asdropStepOnLanePosition: it setstargetStep.position = sourcePositionand thensourceStep.position = targetStep.positionin two separate AJAX requests, briefly leaving two rows with the same position. If the second request fails the database is left in a corrupted state.
async reorderStep(targetStep) {
const sourceStep = this.workflowSteps.find(
(step) => step.id === this.draggedStepId
);
if (!sourceStep || sourceStep.id === targetStep.id) {
return;
}
const sourcePosition = sourceStep.position;
await this.updateStep(targetStep, { position: sourcePosition });
await this.updateStep(sourceStep, { position: targetStep.position });
await this.reloadGraphInPlace();
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Uh oh!
There was an error while loading. Please reload this page.